#include "level_zero.h"
#include <unistd.h>

namespace VirtualR {

LevelZero::LevelZero(std::string dir) : dir_(dir) {
  if (!access(dir_.c_str(), 0)) {
    std::string tmp_file = dir_ + "/index";
    FILE *file = fopen(tmp_file.c_str(), "r");
    fread(&file_count_, sizeof(uint64_t), 1, file);
    fread(&total_byte_size_, sizeof(uint64_t), 1, file);
    for (uint64_t i = 0; i < file_count_; i++) {
        uint64_t no = 0;
        fread(&no, sizeof(uint64_t), 1, file);
        SSTableID id(dir_, no);
        SSTable sst(id);
        sst_list_.emplace_back(sst);
    }
    fclose(file);
  } else {
    int flag = mkdir(dir_.c_str(), 0777);
    if (flag != 0) {
        std::cout << "create dir error" << std::endl;
        assert(false);
    }
    dump_index_to_disk();
  }
}

void LevelZero::add(SkipList &mem, uint64_t no) {
  SSTableID id(dir_, no);
  SSTable table(&mem, id);
  sst_list_.push_back(table);
  file_count_++;
  total_byte_size_ += mem.space();
  // 覆盖写
  dump_index_to_disk();
}

void LevelZero::dump_index_to_disk() {
  std::string tmp_file = dir_ + "/index";
  FILE *file = fopen(tmp_file.c_str(), "w");
  if (file == nullptr) {
    std::cout << "dum index to disk file faild" << std::endl;
    return;
  }
  auto size_d = 0;
  size_d = fwrite(&file_count_, sizeof(uint64_t), 1, file);
  if (size_d != 1) {
    std::cout << "dump_index_to_disk error. file_count_" << std::endl;
    assert(false);
  }
  size_d = fwrite(&total_byte_size_, sizeof(uint64_t), 1, file);
  if (size_d != 1) {
    std::cout << "dump_index_to_disk error. file_count_" << std::endl;
    assert(false);
  }

  for (auto tmp : sst_list_) {
    uint64_t tmp_no = tmp.no();
    size_d = fwrite(&tmp_no, sizeof(uint64_t), 1, file);
    if (size_d != 1) {
      std::cout << "dump_index_to_disk error. file_count_" << std::endl;
      assert(false);
    }
  }
  fclose(file);
}

void LevelZero::get_index_content_for_debug() {
  std::string tmp_file = dir_ + "/index";
  FILE *file = fopen(tmp_file.c_str(), "r");
  uint64_t d_file_count = 0, d_total_byte_size = 0, d_sst_size = 0, d_tmp_sst_no = 0;
  std::vector<uint64_t> d_sst_nos;
  fread(&d_file_count, sizeof(uint64_t), 1, file);
  fread(&d_total_byte_size, sizeof(uint64_t), 1, file);

  for (uint32_t i = 0; i < d_sst_size; i++) {
    fread(&d_tmp_sst_no, sizeof(uint64_t), 1, file);
    d_sst_nos.push_back(d_tmp_sst_no);
  }
  std::cout << "file_count: " << d_file_count << " total_byte: " << d_total_byte_size << std::endl;
  std::cout << "sst nos:";
  for (auto x : d_sst_nos) {
    std::cout << " " << x;
  }
  return;
}

std::vector<Entry_t> LevelZero::get_all_entry() {
  std::vector<std::vector<Entry_t>> inputs;

  for (SSTable &sst : sst_list_) {
    inputs.emplace_back(sst.load());
    sst.remove_file();
  }
  file_count_ = 0;
  total_byte_size_ = 0;
  sst_list_.clear();
  dump_index_to_disk();
  return compact(inputs);
}

uint64_t LevelZero::size() {
  return total_byte_size_;
}

void LevelZero::clear() {
  while (!sst_list_.empty()) {
    sst_list_.back().remove_file();
    sst_list_.pop_back();
  }

  file_count_ = 0;
  total_byte_size_ = 0;
  dump_index_to_disk();
}

std::pair<bool, std::string> LevelZero::search(std::string key) {
  std::pair<bool, std::string> res;
  
  for (uint32_t i = 0; i < file_count_; i++) {
    res = sst_list_[i].search(key);
    
    if (res.first == true && !res.second.empty()) {
        return res;
    }
  }
  return res;
}

}